// -*- indent-tabs-mode: nil -*-
using System;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace seanfoy.oopsnet {
    /// <summary>
    /// Inform end users about uhandled exceptions
    /// </summary>
    public class Oops : Page {
        protected RelatedBugsControl rbc;
        /// <summary>
        /// Generate an HTML representation
        /// of an exception
        /// </summary>
        public static string htmlize(Exception exception) {
            return
                HttpUtility.HtmlEncode(
                    ASPNetErrorHandler.stringify(exception)).Replace("\n", "<br />\n");
        }

        public string htmlUrl() {
            try {
                return HttpUtility.HtmlEncode(Context.Items["seanfoy.oopsnet:requestUrl"].ToString());
            }
            catch (NullReferenceException) {
                //ignore
                return String.Empty;
            }
        }

        public string htmlReferer() {
            try {
                return HttpUtility.HtmlEncode(Context.Items["seanfoy.oopsnet:referrer"].ToString());
            }
            catch (NullReferenceException) {
                //ignore
                return String.Empty;
            }
        }

        /// <summary>
        /// Heuristically find an assembly that
        /// could represent this app
        /// </summary>
        public Assembly getAppAssembly() {
            // e.g., App_global.asax.5ff0b805, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null version 0.0.0.0
            Type appType = 
                Context.ApplicationInstance.GetType();
            Assembly appAssembly = appType.Assembly;
            // e.g., System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a version 2.0.0.0
            Type httpApp = typeof(System.Web.HttpApplication);
            Assembly httpAppAssembly = httpApp.Assembly;
            AssemblyName httpAppAssemblyName = httpAppAssembly.GetName();

            Assembly asm = appAssembly;
            for (Type i = appType; i != httpApp; i = i.BaseType) {
                if (i.Assembly.GetName().GetPublicKeyToken() == httpAppAssemblyName.GetPublicKeyToken()) {
                    // too far
                    break;
                }
                asm = i.Assembly;
                if (i.Assembly.GetName().Version.ToString() != "0.0.0.0") {
                    // far enough
                    break;
                }
            }
            return asm;
        }

        public string appID() {
            Assembly asm = getAppAssembly();
            Version v = asm.GetName().Version;
            return HttpUtility.HtmlEncode(
                       String.Format(
                           "{0} version {1}",
                           asm.FullName,
                           v));
        }

        public Exception exception {
            get {
                return Context.Items["seanfoy.oopsnet:exception"] as Exception;
            }
        }

        public string htmlE() {
            try {
                return htmlize(exception);
            }
            catch (NullReferenceException) {
                //ignore
                return String.Empty;
            }
        }

        public string htmlEMessage() {
            try {
                return HttpUtility.HtmlEncode(exception.Message.ToString());
            }
            catch {
                return String.Empty;
            }
        }

        public string htmlBugWriteup() {
            return String.Format(
                       "Steps to reproduce:\n" +
                       "  1.\n" +
                       "  2.\n" +
                       "  3.\n" +
                       "Expected results:\n" +
                       "Actual results: \n" +
                       "{0}\n\n" +
                       "{1}\n",
                       exception == null ? String.Empty : HttpUtility.HtmlEncode(exception.ToString()),
                       appID());
        }

        private void pageLoad(object sender, EventArgs args) {
            DataBind();
        }

        protected override void OnInit(EventArgs args) {
            Load += new EventHandler(pageLoad);
        }
    }
}
